from typing import Optional
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select
from passlib.context import CryptContext

from app.models.models import User
from app.schemas.schemas import UserCreate
from app.utils.logging import get_logger

# 创建日志记录器
logger = get_logger(__name__)

# 密码哈希工具
import bcrypt

def truncate_password(password: str) -> str:
    """截断密码确保不超过72字节"""
    password_bytes = password.encode('utf-8')
    if len(password_bytes) > 72:
        return password_bytes[:72].decode('utf-8', errors='ignore')
    return password

def get_password_hash(password: str) -> str:
    """手动实现密码哈希，避免使用CryptContext"""
    try:
        # 先截断密码
        truncated_password = truncate_password(password)
        logger.debug(f"Password length after truncation: {len(truncated_password.encode('utf-8'))} bytes")
        
        # 生成盐值
        salt = bcrypt.gensalt()
        
        # 手动哈希 - 直接使用字节数组而不是字符串
        password_bytes = truncated_password.encode('utf-8')
        if len(password_bytes) > 72:
            # 再次确认密码长度不超过72字节
            password_bytes = password_bytes[:72]
            logger.warning("Password was truncated to 72 bytes in get_password_hash")
            
        hashed = bcrypt.hashpw(password_bytes, salt)
        return hashed.decode('utf-8')
    except Exception as e:
        logger.error(f"Error in get_password_hash: {str(e)}")
        raise

def verify_password(plain_password: str, hashed_password: str) -> bool:
    """手动验证密码"""
    try:
        # 先截断密码
        truncated_password = truncate_password(plain_password)
        
        # 手动验证 - 直接使用字节数组
        password_bytes = truncated_password.encode('utf-8')
        if len(password_bytes) > 72:
            # 再次确认密码长度不超过72字节
            password_bytes = password_bytes[:72]
            logger.warning("Password was truncated to 72 bytes in verify_password")
            
        return bcrypt.checkpw(password_bytes, hashed_password.encode('utf-8'))
    except Exception as e:
        logger.error(f"Error in verify_password: {str(e)}")
        return False

async def get_user_by_username(db: AsyncSession, username: str) -> Optional[User]:
    """通过用户名获取用户"""
    result = await db.execute(select(User).filter(User.username == username))
    return result.scalars().first()

async def create_user(db: AsyncSession, user: UserCreate) -> User:
    """创建用户"""
    try:
        # 确保密码不超过72字节
        hashed_password = get_password_hash(user.password)
        
        # 创建用户时不包含secret_key字段
        user_data = {
            "username": user.username,
            "password_hash": hashed_password,
            "role": user.role
        }
        db_user = User(**user_data)
        db.add(db_user)
        await db.commit()
        await db.refresh(db_user)
        return db_user
    except Exception as e:
        # 捕获并记录所有异常
        logger.error(f"Error creating user: {str(e)}")
        # 如果是密码长度错误，打印更详细的调试信息
        if "password cannot be longer than 72 bytes" in str(e):
            password_bytes = user.password.encode('utf-8')
            logger.error(f"Password length: {len(password_bytes)} bytes")
        raise

async def authenticate_user(db: AsyncSession, username: str, password: str) -> Optional[User]:
    """认证用户"""
    user = await get_user_by_username(db, username)
    if not user:
        return None
    if not verify_password(password, user.password_hash):
        return None
    return user
